package pluginUtils;

import sliceformUtils.DroiteSpace3D;
import sliceformUtils.ImagePlan;

/** Classe décrivant une cyclide de Dupin.
 * 
 * @author decomite
 *
 */
public class DupinCyclide {
	
	protected enum CyclideType{RING,HORN,SPINDLE}; 


	/** Notations from "Dupin Cyclide Blends between Quadric...
	 * 
	 */
	protected double a,mu,c,b;
	protected CyclideType type;  
	
	public DupinCyclide(double u,double v,double w){
		this.a=u; 
		this.mu=v; 
		this.c=w; 
		this.b=Math.sqrt(a*a-c*c); 
		if((c>=0)&&(mu>c)&&(a>=mu)) this.type=CyclideType.RING;  
		if((mu>0)&&(c>=mu)&&(a>c)) this.type=CyclideType.HORN;  
		if((c>=0)&&(a>=c)&&(mu>a)) this.type=CyclideType.SPINDLE;  
	}

	public double getA() {
		return a;
	}

	public double getMu() {
		return mu;
	}

	public double getC() {
		return c;
	}

	public double getB() {
		return b;
	}

	public CyclideType getType() {
		return type;
	}

	protected double calculX(double th, double al) {
		double den=a-c*Math.cos(th)*Math.cos(al); 
		return (mu*(c-a*Math.cos(th)*Math.cos(al))+b*b*Math.cos(th))/den; 
	}
	
	protected double calculY(double th, double al) {
		double den=a-c*Math.cos(th)*Math.cos(al); 
		return b*Math.sin(th)*(a-mu*Math.cos(al))/den; 
	}

	protected double calculZ(double th, double al) {
		double den=a-c*Math.cos(th)*Math.cos(al); 
		return b*Math.sin(al)*(c*Math.cos(th)-mu)/den; 
	}
	
	/** Retourne le cercle vertical pour l'angle th */
	public Circle3D cercleTheta(double th){
		// calcul du plan
		Pos3D p1=new Pos3D(calculX(th, 0),calculY(th,0),calculZ(th,0)); 
		Pos3D p2=new Pos3D(calculX(th, Math.PI/3),calculY(th,Math.PI/3),calculZ(th,Math.PI/3)); 
		Pos3D p3=new Pos3D(calculX(th, -Math.PI/3),calculY(th,-Math.PI/3),calculZ(th,-Math.PI/3)); 
		Plane p=new Plane(p1,p2,p3); 
		// Centre
		// Milieu de p1,p2
		Pos3D m1=Pos3D.middle(p1,p2); 
		Pos3D vecP1P2=Pos3D.sub(p2,p1);
		Pos3D direction1=Pos3D.produitvectoriel(vecP1P2, p.getVecteurNormal()); 
		DroiteSpace3D biss1_2=new DroiteSpace3D(m1, direction1); 
		
		// Milieu de p1,p3
		Pos3D m2=Pos3D.middle(p1,p3); 
		Pos3D vecP1P3=Pos3D.sub(p3,p1);
		Pos3D direction2=Pos3D.produitvectoriel(vecP1P3, p.getVecteurNormal()); 
		DroiteSpace3D biss1_3=new DroiteSpace3D(m2, direction2); 
		
		Pos3D center=DroiteSpace3D.intersection(biss1_2,biss1_3); 
		/*
		System.out.println("distances : "+Pos3D.distance(p1, center)); 
		System.out.println("distances : "+Pos3D.distance(p2, center)); 
		System.out.println("distances : "+Pos3D.distance(p3, center)); 
		*/
		// Rayon
		double rayon=Pos3D.distance(p1, center); 
		
		return new Circle3D(center, rayon, p); 
	}
	
	/** Retourne le cercle a peu pres horizontal pour l'angle passe en parametre */ 
	public Circle3D cercleAlpha(double angle){
		// calcul du plan
		Pos3D p1=new Pos3D(calculX(0, angle),calculY(0,angle),calculZ(0,angle)); 
		Pos3D p2=new Pos3D(calculX(Math.PI/3,angle),calculY(Math.PI/3,angle),calculZ(Math.PI/3,angle)); 
		Pos3D p3=new Pos3D(calculX(-Math.PI/3,angle),calculY(-Math.PI/3,angle),calculZ(-Math.PI/3,angle)); 
		Plane p=new Plane(p1,p2,p3); 
		// Centre
		// Milieu de p1,p2
		Pos3D m1=Pos3D.middle(p1,p2); 
		Pos3D vecP1P2=Pos3D.sub(p2,p1);
		Pos3D direction1=Pos3D.produitvectoriel(vecP1P2, p.getVecteurNormal()); 
		DroiteSpace3D biss1_2=new DroiteSpace3D(m1, direction1); 
		
		// Milieu de p1,p3
		Pos3D m2=Pos3D.middle(p1,p3); 
		Pos3D vecP1P3=Pos3D.sub(p3,p1);
		Pos3D direction2=Pos3D.produitvectoriel(vecP1P3, p.getVecteurNormal()); 
		DroiteSpace3D biss1_3=new DroiteSpace3D(m2, direction2); 
		
		Pos3D center=DroiteSpace3D.intersection(biss1_2,biss1_3); 
		/*
		System.out.println("distances : "+Pos3D.distance(p1, center)); 
		System.out.println("distances : "+Pos3D.distance(p2, center)); 
		System.out.println("distances : "+Pos3D.distance(p3, center)); 
		*/
		// Rayon
		double rayon=Pos3D.distance(p1, center); 
		
		return new Circle3D(center, rayon, p); 
	}
	
	public double implicit1(double x, double y, double z){
		double terme1=x*x+y*y+z*z-mu*mu+b*b; 
		terme1=terme1*terme1; 
		double terme2=4*(a*x-c*mu)*(a*x-c*mu);
		double terme3=4*b*b*y*y; 
		return terme1-terme2-terme3; 
	}
	
	public double implicit2(double x, double y, double z){
		double terme1=x*x+y*y+z*z-mu*mu-b*b; 
		terme1=terme1*terme1; 
		double terme2=4*(c*x-a*mu)*(c*x-a*mu);
		double terme3=4*b*b*z*z; 
		return terme1-terme2+terme3; 
	}
	
	public static void main(String[] args) {
		DupinCyclide dc=new DupinCyclide(5, 2, 1); 
		Circle3D origine=dc.cercleTheta(Math.PI/2); 
		ImagePlan essai=new ImagePlan(origine); 
		for(int i=0;i<6;i++)
		{
			Circle3D courant=dc.cercleAlpha(2*Math.PI*i/6); 
			Plane secant=courant.getPlan(); 
			DroiteSpace3D trace=Plane.inter(secant, origine.getPlan()); 
			essai.add(trace); 
		}
	}
	
}
